﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace cosoware.RayTracer.Math
{
    /// <summary>
    /// Matrix strict.
    /// </summary>
    public struct Matrix
    {
        /// <summary>
        /// Implements the multiplication operator.
        /// </summary>
        /// <param name="a">The fist matrix.</param>
        /// <param name="b">The second matrix.</param>
        /// <returns>The result of the multiplication operator.</returns>
        public static Matrix operator *(Matrix a, Matrix b)
        {
            Matrix m = new Matrix(a.Rows, b.Columns);
            for (int i = 0; i < a.Rows; i++)
                for (int j = 0; j < a.Columns; j++)
                    for (int k = 0; k < a.Columns; k++)
                        m._data[i][j] += a._data[i][k] * b._data[k][j];
            return m;
        }

        /// <summary>
        /// Numbers in matrix
        /// </summary>
        private readonly double[][] _data;

        /// <summary>
        /// Initializes a new instance of the <see cref="Matrix"/> struct.
        /// </summary>
        /// <param name="rows">The rows number.</param>
        /// <param name="columns">The columns number.</param>
        public Matrix(int rows, int columns)
        {
            _data = (double[][])Array.CreateInstance(typeof(double), rows, columns);
        }

        /// <summary>
        /// Gets or sets the <see cref="System.Double"/> with the specified row and column.
        /// </summary>
        /// <value></value>
        public double this[int row, int column]
        {
            get { return _data[row][column]; }
            set { _data[row][column] = value; }
        }

        /// <summary>
        /// Gets the rows number.
        /// </summary>
        /// <value>The rows number.</value>
        public int Rows
        {
            get { return _data.GetLength(0); }
        }

        /// <summary>
        /// Gets the columns number.
        /// </summary>
        /// <value>The columns number.</value>
        public int Columns
        {
            get { return _data.GetLength(1); }
        }

        /// <summary>
        /// Gets the row.
        /// </summary>
        /// <param name="index">The index.</param>
        /// <returns></returns>
        public IEnumerable<double> GetRow(int index)
        {
            for (int i = 0; i < Columns; i++)
                yield return _data[index][i];
        }

        /// <summary>
        /// Gets the row.
        /// </summary>
        /// <param name="index">The index.</param>
        /// <returns></returns>
        public IEnumerable<double> GetCloumn(int index)
        {
            for (int i = 0; i < Rows; i++)
                yield return _data[i][index];
        }

        /// <summary>
        /// Returns the string representation of this matrix.
        /// </summary>
        /// <returns>
        /// A <see cref="T:System.String"/> representing of this matrix.
        /// </returns>
        public override string ToString()
        {
            StringBuilder sb = new StringBuilder();
            sb.Append('[');
            for (int i = 0; i < _data.GetLength(0); i++)
            {
                sb.Append('[');
                for (int j = 0; i < _data.GetLength(1); i++)
                {
                    sb.Append(_data[i][j]);
                    sb.Append(',');
                }
                sb.Append(']');
                sb.Append(',');
            }
            sb[sb.Length - 1] = ']';
            return sb.ToString();
        }
    }
}
